package org.cuit.seon.explore.aop;

import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

/**
 * todo ： 摘下命运的枷锁，打破双非的限制
 * todo : 自己实验一下在AOP中，使用WebUtils进行renderingString来写一个自己写的RestControllerAdvice。由此猜测，RestControllerAdvice也就是一个AOP来进行实现的。
 *
 * @author wuwen
 */
@Aspect
@Component
@Slf4j
/*
 * 对于本注解使用在AOP切面上需要注意的事情，不能在Spring环境中直接将自己定义的AOP的Order置于最高优先级
 * 因为Spring会自己在容器内加入一下ExposeInvocationInterceptor，这个东西的作用就是让AOP起作用的类。
 */
@Order(Ordered.HIGHEST_PRECEDENCE + 2)
public class WebInterfaceLogAop {

    /*
    学习笔记：
    操作日志所说的就是指在某个时间点，某个对象对某个事物做出了某个操作。
    而AOP其实就是在运行的时候，动态的将代码切入到类的指定方法或是指定位置上的编程思想就是面向切面的编程。
    在典型的around的AOP执行模型中，在try里的可以理解为前置通知，catch理解为异常通知，finally就是后置通知。
     */

//    @Pointcut("@annotation(org.cuit.seon.explore.annotation.AopAnnotationPointCutExplore)")
//    public void aop() {
//    }

    // 有一个写execution的小技巧就是，想要给哪个方法添加通知，就先把这个方法的全限定名拿出来，然后在表达式里进行匹配即可
//    @Pointcut("execution(* org.cuit.seon.explore.controller.*.*(..))") // 只识别controller包下的类中的所有方法
//    @Pointcut("execution(* org.cuit.seon.explore.controller..*.*.*(..))") // 识别controller下所有子包(仅含子包)的任何方法
    @Pointcut("execution(* org.cuit.seon.explore.controller..*.*(..))") // 识别controller包及其子包下的所有类的任何方法
    public void log() {
    }

    @Around(value = "log()")
    public Object aopHandle(ProceedingJoinPoint joinPoint) throws Throwable {
        //执行目标方法
        Object proceed = null;
        try {
            log.info("我是AOP一号 before");
            proceed = joinPoint.proceed();
        } catch (Exception e) {
            log.error("我是AOP一号 exception " + e);
            //避免覆盖全局异常
            throw e;
        } finally {
            log.info("我是AOP一号 after");
        }
        return proceed;
    }
}